<?php

namespace app\company\controller;

use app\common\controller\CompanyController;
use app\common\enum\order\DealerOrderStatus;
use app\common\enum\order\GoodsType;
use app\common\enum\order\OrderStatus;
use app\common\enum\order\PickOrderStatus;
use app\common\enum\purchase\OrderType;
use app\common\exception\BaseException;
use app\common\Jobs\ReportGoodsOutJob;
use app\common\model\AccountRecord;
use app\common\model\DealerCharge;
use app\common\model\DealerGoods;
use app\common\model\DealerGoodsSpec;
use app\common\service\annotation\ControllerAnnotation;
use app\common\service\annotation\NodeAnnotation;
use app\company\model\CompanyOrder;
use app\company\model\CompanyOrderDetail;
use app\company\model\CompanyPickOrder;
use app\company\model\CompanyTransferOrder;
use app\company\model\CompanyTransferOrderDetail;
use app\company\model\DealerOrder;
use app\company\model\DealerOrderDetail;
use app\common\model\Driver;
use app\Request;
use think\App;
use think\facade\Queue;
use think\response\Json;

/**
 * @ControllerAnnotation(title="拣货单")
 */
class PickOrder extends CompanyController
{
    public function __construct(App $app)
    {
        parent::__construct($app);
        $this->model = new CompanyPickOrder();
        $this->sort  = ['id' => 'desc'];
        $this->each  = true;
    }

    public function each($list)
    {
        return $list->each(function ($vo) {
            if ($vo->type == 1) {
                $orderIds   = explode(',', $vo->company_order_ids);
                $driverIds  = (new CompanyOrder())->whereIn('id', $orderIds)->column('driver_id');
                $driver     = $driverIds ? (new Driver())->whereIn('id', $driverIds)->column('name') : null;
                $vo->driver = $driver ? implode(',', $driver) : null;
                $vo->pick   = (new CompanyOrderDetail())->field('dealer_goods_id,dealer_goods_spec_id,goods_type,
                sale_price,true_price,sum(num) as num,sum(real_num) as real_num,sum(total_price) as total_price')
                    ->with([
                        'goods' => function ($query) {
                            $query->with([
                                'brand'  => function ($query) {
                                    $query->field('id,name');
                                },
                                'cate'   => function ($query) {
                                    $query->field('id,name');
                                },
                                'zBrand' => function ($query) {
                                    $query->field('id,name');
                                },
                                'zCate'  => function ($query) {
                                    $query->field('id,name');
                                }
                            ])->withTrashed();
                        },
                        'goodsSpec' => function ($query) {
                            $query->withTrashed();
                        }
                    ])
                    ->whereIn('company_order_id', $orderIds)
                    ->whereIn('goods_type', [GoodsType::SALE, GoodsType::GIFT])
                    ->group('dealer_goods_spec_id')->select()->each(function ($item) {
                        $item->spec = $item->goodsSpec;
                        unset($item->goodsSpec);
                    });
            } elseif ($vo->type == 2) {
                $orderIds   = explode(',', $vo->dealer_order_ids);
                $vo->driver = null;
                $vo->pick   = (new DealerOrderDetail())->with([
                    'goods' => function ($query) {
                        $query->with([
                            'brand'  => function ($query) {
                                $query->field('id,name');
                            },
                            'cate'   => function ($query) {
                                $query->field('id,name');
                            },
                            'zBrand' => function ($query) {
                                $query->field('id,name');
                            },
                            'zCate'  => function ($query) {
                                $query->field('id,name');
                            }
                        ])->withTrashed();
                    },
                    'spec' => function ($query) {
                        $query->withTrashed();
                    }
                ])
                    ->whereIn('dealer_order_id', $orderIds)->select();
            } elseif ($vo->type == 3) {
                $orderIds   = explode(',', $vo->transfer_order_ids);
                $vo->driver = null;
                $vo->pick   = (new CompanyTransferOrderDetail())->with([
                    'goods' => function ($query) {
                        $query->with([
                            'brand'  => function ($query) {
                                $query->field('id,name');
                            },
                            'cate'   => function ($query) {
                                $query->field('id,name');
                            },
                            'zBrand' => function ($query) {
                                $query->field('id,name');
                            },
                            'zCate'  => function ($query) {
                                $query->field('id,name');
                            }
                        ]);
                    },
                    'spec' => function ($query) {
                        $query->withTrashed();
                    }
                ])
                    ->whereIn('t_oid', $orderIds)->select();
            }

            $detail = $vo->pick->toArray();
            $small = $large = $middle = 0;
            array_walk($detail, function ($v) use (&$small,&$large,&$middle) {
                $spec = $v['goodsSpec']??$v['spec'];
                switch ($spec['unit_type']){
                    case 1:
                        $small += $v['num']??$v['transfer_num'];
                        break;
                    case 2:
                        $large += $v['num']??$v['transfer_num'];
                        break;
                    case 3:
                        $middle += $v['num']??$v['transfer_num'];
                        break;
                    default:
                        break;
                }
            });
            $largeStr = $large ? $large.'大' : '';
            $middleStr = $middle ? $middle.'中' : '';
            $smallStr = $small ? $small.'小' : '';
            $vo->goods_total = $largeStr.$middleStr.$smallStr;
        });
    }

    /**
     * @NodeAnnotation (title="确认出库")
     * TODO 更新实际库存在这儿做
     */
    public function modify(Request $request): Json
    {
        try {
            $this->checkPost();
            $post = $request->post();

            $row = $this->model->find($post['id']);
            if (!$row) return $this->error('当前数据不存在！');
            //            if ($row->pick_order_status != PickOrderStatus::WAIT_PICK) return $this->error('当前状态不允许修改！');
            $this->model->transaction(function () use ($post, $row) {
                $orderInfo               = $row->toArray();

                // 更新出库单状态
                if ($row->company_order_ids) {
                    //销售出库单
                    // 更新库存
                    $this->updateStock($row);
                    // 更新订单状态
                    (new CompanyOrder())->whereIn('id', explode(',', $row->company_order_ids))->save(['out_status'=>2]);
                    // 2024.11.15 生成经销商分账单明细，对账单填入数据
                    $this->createFz($row);
                }
                if ($row->dealer_order_ids) {
                    // 采退单
                    $this->updateDealerStock($row);
                }
                if ($row->transfer_order_ids) {
                    // 调拨单
                    $this->updateTransferStock($row);
                }
                $row->save([
                                   $post['field'] => $post['value'],
                           ]);

                // 异步埋点统计出库情况
                Queue::push(ReportGoodsOutJob::class, $orderInfo, 'report_goods_out');
            });
        } catch (\Exception $e) {
            return $this->error($e->getMessage() . $e->getLine());
        }
        return $this->success('操作成功');
    }


    /**
     * 根据销售出库更新库存
     */
    private function updateStock(mixed $row): void
    {
        (new CompanyOrderDetail())->where('company_order_id', 'in', explode(',', $row->company_order_ids))
                                  ->select()
                                  ->each(function ($item)
                                  {
                                      $stockInfo = (new DealerGoodsSpec())->where('id', $item->dealer_goods_spec_id)->withTrashed()
                                                                          ->find();
                                      // 更新经销商商品库存
                                      //                                      (new DealerGoodsSpec())->where('id', $item->dealer_goods_spec_id)->dec('freeze_stock', $item->num)->save();
                                      // 更新实际库存
                                      $goodsInfo = (new DealerGoods())->where('id', $item->dealer_goods_id)->withTrashed()->find();
                                      if ($goodsInfo->warehouse_stock < $item->num * $stockInfo['ratio'])
                                          throw new BaseException(['message' => '商品【' . $goodsInfo['name'] . '--' . $stockInfo['name'] . '】库内库存不足，无法出库']);
                                      if(!$stockInfo['ratio']) throw new BaseException(['message' => '商品【'. $stockInfo['name'] .'】规格比例不能为空']);
                                      $goodsInfo->dec('warehouse_stock', $item->num * $stockInfo['ratio'])->save();
                                      // 自提订单状态已完成
                                      $is_self_order = (new CompanyOrder())->where('id',$item->company_order_id)->value('is_self_order');
                                      if($is_self_order == 2) (new CompanyOrder())->where('id',$item->company_order_id)->save(['order_status'=>2,'update_time'=>time()]);
                                  });
        (new CompanyOrder())->where('id', 'in', explode(',', $row->company_order_ids))->save(['out_status'=>2,'update_time'=>time()]);
    }

    /**
     * 更新退货订单状态以及经销商商品库存
     */
    private function updateDealerStock(mixed $row): void
    {
        (new DealerOrder())->where('id', 'in', explode(',', $row->dealer_order_ids))->where('order_type', OrderType::CT)
            ->update(['order_status' => DealerOrderStatus::FINISHED,'update_time'=>time()]);
        // 更新库存
        (new DealerOrderDetail())->where('dealer_order_id', 'in', explode(',', $row->dealer_order_ids))
            ->select()
            ->each(function ($item) {
                $stockInfo = (new DealerGoodsSpec())->where('id', $item->dealer_goods_spec_id)->withTrashed()
                    ->find();
                // 更新经销商商品库存
                //                                     (new DealerGoodsSpec())->where('id', $item->dealer_goods_spec_id)
                //                                                            ->dec('freeze_stock', $item->real_num)
                //                                                            ->save();

                // 更新实际库存
                $goodsInfo = (new DealerGoods())->where('id', $item->dealer_goods_id)->withTrashed()->find();
                if ($goodsInfo->warehouse_stock < $item->num * $stockInfo['ratio'])
                throw new BaseException(['message' => '商品【' . $goodsInfo['name'] . '--' . $stockInfo['name'] . '】库内库存不足，无法出库']);
                $goodsInfo->dec('warehouse_stock', $item->num * $stockInfo['ratio'])->save();
            });
    }

    /**
     * 根据调拨单扣减实际仓库库存
     */
    private function updateTransferStock(mixed $row): void
    {
        $ids = explode(',', $row->transfer_order_ids);
        // 过滤已经确认出库的订单
        $ids = (new CompanyTransferOrder())->where('id', 'in', $ids)
            ->where('order_status', 1)
            ->column('id');
        // 更新调拨单状态
        (new CompanyTransferOrderDetail())->where('t_oid', 'in', $ids)
            ->select()
            ->each(function ($item) {
                $stockInfo = (new DealerGoodsSpec())->where('id', $item->dealer_goods_spec_id)->find();
                if (!$stockInfo->ratio) throw new BaseException(['message' => '商品规格比例不能为空']);
                // 更新实际库存
                (new DealerGoods())->where('id', $item->dealer_goods_id)
                    ->dec('warehouse_stock', $item->transfer_num * $stockInfo->ratio)->save();
            });
        // 更新调拨单状态
        (new CompanyTransferOrder())->where('id', 'in', $ids)->save(['check_status' => 3,'update_time'=>time()]);
    }

    /**
     * 处理分账，生成经销商分账单明细，对账单填入数据
     * @param $pickInfo
     * @return void
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private function createFz($pickInfo): void
    {
        // 实例化模型 （有些查询以后时间放到model里写个统一的方法，兼容不同情况传参就行）
        $dealerChargeModel       = new DealerCharge();
        $accountModel            = new AccountRecord();
        $companyOrderDetailModel = new CompanyOrderDetail();
        $dealerModel             = new \app\common\model\Dealer();
        // 根据经销商分组，拣货单可能是不同经销商合并到一起的，最好把桐一经销商的销售单放一起，再去操作，省的乱
        $grouped_array = arrayGroupBy($pickInfo->detail->toArray(), function ($item) {
            return $item['dealer_id'];
        });
        // 循环经销商分组，生成分账单明细
        foreach ($grouped_array as $key => $value) {
            // 计算出库金额
            $outMoney = $companyOrderDetailModel->field('sum(sale_price * num) as money')
                ->where(
                    'company_order_id',
                    'in',
                    array_column($value, 'company_order_id')
                )->find();
            // 经销商服务费率
            $dealerInfo = $dealerModel->field('id,name,tc_rate,tp_rate,tx_rate')->where('id', $key)->find();

            // 服务费
            $tc_money = $dealerInfo->tc_rate ? bcmul(bcdiv($dealerInfo->tc_rate, 100, 2), $outMoney['money'], 2) : 0;
            $tp_money = $dealerInfo->tp_rate ? bcmul(bcdiv($dealerInfo->tp_rate, 100, 2), $outMoney['money'], 2) : 0;
            $tx_money = $dealerInfo->tx_rate ? bcmul(bcdiv($dealerInfo->tx_rate, 100, 2), $outMoney['money'], 2) : 0;

            $serviceMoney = $tc_money + $tp_money + $tx_money;
            // 查询经销商对账信息
            $accountInfo = $accountModel->where('company_id', $this->companyId)
                ->where('payee_type', AccountRecord::DEALER)
                ->where('payee_id', $key)->find();
            // 判断对账信息是否存在，不存在就创建
            if (!$accountInfo) {
                $accountData = [
                    'company_id' => $this->companyId,
                    'payee_type' => AccountRecord::DEALER,
                    'payee_id'   => $key,
                    'fz_money'   => $serviceMoney,
                ];
                $accountModel->save($accountData);
                $accountId = $accountModel->getKey();
            } else {
                $accountInfo->inc('fz_money', $serviceMoney)->save();
                $accountId = $accountInfo->id;
            }
            // 保存分账单明细
            //tc_rate,tp_rate,tx_rate
            $DealerChargeData = [
                'company_id'            => $this->companyId,
                'dealer_id'             => $key,
                'company_pick_order_id' => $pickInfo->id,
                'account_record_id'     => $accountId,
                'out_money'             => $outMoney['money'],
                'tc_rate'               => $dealerInfo->tc_rate,
                'tp_rate'               => $dealerInfo->tp_rate,
                'tx_rate'               => $dealerInfo->tx_rate,
                'money'                 => $serviceMoney,
            ];
            $dealerChargeModel->save($DealerChargeData);
        }
    }
}
